#include <stdio.h>
#include <ctype.h>

//E -> TE'
//E' -> +TE' | e
//T -> FT'
//T' -> *FT' | e
//F -> NUM | (E)
//FIRST(E) = {NUM, LEFTB}
//FIRST(E') = {PLUS, e}
//FIRST(T) = {NUM, LEFTB}
//FIRST(T') = {MULT, e}
//FIRST(F) = {NUM, LEFTB}
//FOLLOW(E) = {$, RIGHTB}
//FOLLOW(E') = {$, RIGHTB}
//FOLLOW(T) = {PLUS, RIGHTB, $}
//FOLLOW(T') = {PLUS, RIGHTB, $}
//FOLLOW(F) = {MULT, PLUS, RIGHTB, $}

enum TOKEN {PLUS, MULT, NUM, END, ERR, LEFTB, RIGHTB};
char lookahead;
enum TOKEN token;
int num;
int error = 0;
FILE *fp;

void lexical(FILE *fp);
int match(enum TOKEN x);
int E();
int E_();
int T();
int T_();
int F();


//return 0 if success, return 1 otherwise
int match(enum TOKEN x) {
	if(token == x) {
		lexical(fp);
		return 0;
	} else {
		error = 1;
		return 1;
	}
}

//E -> TE'
int E() {
    //printf("1\n");
    int temp1 = T(), temp2 = E_();
    //printf("E() temp1 %d, temp2 %d\n",temp1, temp2);
    return temp1 + temp2;
}

//E_ -> +TE'|e
int E_() {
    //printf("11\n");
    if(token == PLUS)
    {
        match(token);
        int temp1 = T(), temp2 = E_();
        //printf("E_() temp1 %d, temp2 %d\n",temp1, temp2);
        return temp1 + temp2;
    }
    else if (token == END || token == RIGHTB)
    {

    }
    else
    {
        error = 1;
        if(token == ERR)
        {
            return 1;
        }
        printf("Error at %d", num);
        return 1;
    }
	return 0;
}

//T -> FT'
int T() {
    //printf("111\n");
    int temp1 = F(), temp2 = T_();
    //printf("T() temp1 %d, temp2 %d\n",temp1, temp2);
    return temp1*temp2;
}


//T' -> *FT' | e
int T_() {
    //printf("1111\n");
    int temp1, temp2;
    if(token == MULT)
    {
        match(token);
        temp1 = F();
        temp2 = T_();
        //printf("T_() temp1 %d, temp2 %d\n",temp1, temp2);
        if(temp2 == 1)
            return temp1;
        else
            return temp1+temp2;
    }
    else if (token == RIGHTB || token == PLUS || token == END)
    {
        return 1;
    }
    else
    {
        error = 1;
        if(token == ERR)
        {
            return 1;
        }
        printf("error at %d\n", num);
        return 1;
    }
}

//F -> NUM | (E)
int F() {
    //printf("11111\n");
    int temp, number;
    if(token == NUM)
    {
        //printf("matching\n");
        number = num;
        match(token);
        //printf("F() num %d\n", num);
        return number;
    }
    else
    {
        if(match(LEFTB))
        {
            printf("stupid char %c\n", lookahead);
            error = 1;
            return 1;
        }
        temp = E();
        //printf("F() temp %d\n", temp);
        if(match(RIGHTB)) //0 success 1 error
        {
            printf("Unmatched right bracket\n");
            error = 1;
            return 1;
        }
        return temp;
    }
	return 0;
}





void lexical(FILE *fp) {

	lookahead = getc(fp);
	num = 0;

	while(lookahead == ' ' || lookahead == '\t' || lookahead == '\n') {
		lookahead = getc(fp);
	}

	if(isdigit(lookahead)) {
		num = 0;
		while(isdigit(lookahead)) {
			token = NUM;
			num = num * 10 + lookahead - '0';
			lookahead = getc(fp);
		}
		//printf("lex %d\n", num);
		ungetc(lookahead, fp);
		return;
	} else if (lookahead == '+') {
		token = PLUS;
		return;
	} else if (lookahead == '*') {
		token = MULT;
		return;
	} else if(lookahead == EOF) {
		token = END;
		return;
	}else if(lookahead == '(') {
		token = LEFTB;
		return;
	} else if(lookahead == ')') {
		token = RIGHTB;
		return;
	} else {
		error = 1;
		token = ERR;
		return;
	}
}

int main(int argc, char **argv) {
	int  res = 0;
	if(argc < 2) {
		printf("insufficient arguments");
		return 1;
	}
	fp = fopen(argv[1], "r");

	lexical(fp);
	res = E();
	if(!error) {
		printf("%d\n", res);
	} else {
		printf("There are errors\n");
	}

	fclose(fp);
	return 0;

}
